﻿using System;
using Microsoft.Xna.Framework;
using WindowsGame.Enums;
using WindowsGame.GameObjects;
using WindowsGame.Library.ProxyObjects;

namespace WindowsGame.Components
{
	public class PhysicsComponent : BaseGameComponent
	{
		private Vector3 velocity;
		private Vector3 position, rotation;
		private Vector3 prevPosition, prevRotation;
		private Matrix scaleMatrix;
		private Matrix worldMatrix;

		public override void Initialize(GameObject owner, ProxyComponent proxyComponent)
		{
			base.Initialize(owner, proxyComponent);
			rotation = new Vector3(MathHelper.ToRadians(Rotation.X), MathHelper.ToRadians(Rotation.Y), MathHelper.ToRadians(Rotation.Z));

			velocity = Vector3.Zero;
			this.position = Position;
			prevPosition = position;
			prevRotation = rotation;

			scaleMatrix = Matrix.CreateScale(ModelScale);
			worldMatrix = CalcWorldMatrix();
		}

		public void UpdateRotation(Direction direction)
		{
			if (direction == Direction.None)
			{
				return;
			}

			rotation.Z += (Int32)direction * RotateScale;
		}

		public void UpdatePosition(TimeSpan elapsedTime, Vector3 acceleration)
		{
			// Do the basic acceleration / velocity / position updates.
			velocity += Vector3.Multiply(acceleration, (Single)elapsedTime.TotalSeconds);
			position += Vector3.Multiply(velocity, (Single)elapsedTime.TotalSeconds);

			if (position.X > BoundRight)
				position.X = BoundLeft;
			else if (position.X < BoundLeft)
				position.X = BoundRight;

			if (position.Y > BoundBottom)
				position.Y = BoundTop;
			else if (position.Y < BoundTop)
				position.Y = BoundBottom;
		}

		public void UpdateVelocity(Vector3 velocity)
		{
			this.velocity = velocity;
		}

		public void Update()
		{
			if (position == prevPosition && rotation == prevRotation)
			{
				return;
			}
			
			worldMatrix = CalcWorldMatrix();
			prevPosition = position;
			prevRotation = rotation;
		}

		public Single ModelScale	{ get; set; }
		public Single RotateScale	{ get; set; }
		public Int32  BoundLeft		{ get; set; }
		public Int32  BoundRight	{ get; set; }
		public Int32  BoundTop		{ get; set; }
		public Int32  BoundBottom	{ get; set; }
		
		public Vector3 Position
		{
			get { return position; }
			set { position = value; }
		}
		public Vector3 Rotation
		{
			get { return rotation; }
			set { rotation = value; }
		}

		public Vector3 Velocity { get { return velocity; } }
		public Matrix WorldMatrix { get { return worldMatrix; } }

		private Matrix CalcWorldMatrix()
		{
			Matrix rotationMatrixX = Matrix.CreateRotationX(rotation.X);
			Matrix rotationMatrixY = Matrix.CreateRotationY(rotation.Y);
			Matrix rotationMatrixZ = Matrix.CreateRotationZ(rotation.Z);
			Matrix translationMatrix = Matrix.CreateTranslation(position);

			worldMatrix = scaleMatrix * rotationMatrixX * rotationMatrixY * rotationMatrixZ * translationMatrix;
			return worldMatrix;
		}
	}
}